package com.tqz.dt.interceptors;

import com.tqz.dt.attribute.GlobalTransactionAttribute;
import com.tqz.dt.attribute.DefaultGlobalTransactionAttribute;
import com.tqz.dt.source.GlobalTransactionAttributeSource;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * <p>事务拦截器抽象类
 *
 * @author tianqingzhao
 * @since 2021/7/7 14:40
 */
@Data
@Slf4j
public abstract class AbstractGlobalTransactionalInterceptor implements BeanFactoryAware {

    private BeanFactory beanFactory;

    private GlobalTransactionAttributeSource angleTransactionAttributeSource;

    private PlatformTransactionManager transactionManager;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
        // 获取事务属性
        GlobalTransactionAttribute txAttr = getAngleTransactionAttributeSource().getTransactionAttribute(method, targetClass);
        // 获取事务管理器
        PlatformTransactionManager transactionManager = determineTransactionManager();

        Connection connection = openTransactionIfNecessary(transactionManager);
        Object retVal = null;
        try {
            // 调用目标函数
            retVal = invocation.proceedWithInvocation();
            // 提交事务
            connection.commit();
        } catch (Exception e) {
            log.error("执行目标方法异常:{}", e.getMessage());
            // 回滚事务
            completeTransactionAfterThrowing(connection, txAttr, e);
            throw e;
        } finally {
            connection.close();
        }

        return retVal;
    }

    /**
     * 开启事务 如果有必要的话
     *
     * @param txManager 事务管理器
     * @return
     */
    protected Connection openTransactionIfNecessary(PlatformTransactionManager txManager) throws SQLException {
        DataSourceTransactionManager dataSourceTransactionManager = (DataSourceTransactionManager) txManager;

        DataSource dataSource = dataSourceTransactionManager.getDataSource();
        //获取数据库连接
        Connection connection = dataSource.getConnection();

        if (connection.getAutoCommit()) {
            connection.setAutoCommit(false);
        }
        return connection;
    }

    /**
     * 获取事务管理器
     *
     * @return {@link PlatformTransactionManager}
     */
    protected PlatformTransactionManager determineTransactionManager() {
        return beanFactory.getBean(PlatformTransactionManager.class);
    }

    protected interface InvocationCallback {

        Object proceedWithInvocation() throws Throwable;
    }

    /**
     * 处理异常是否需要被回滚
     *
     * @param angleTransactionAttribute
     * @param e
     */
    public void completeTransactionAfterThrowing(Connection connection, GlobalTransactionAttribute angleTransactionAttribute, Exception e) throws SQLException {
        DefaultGlobalTransactionAttribute defaultAngleTransactionAttribute = (DefaultGlobalTransactionAttribute) angleTransactionAttribute;
        if (defaultAngleTransactionAttribute.rollbackOn(e)) {
            connection.rollback();
        } else {
            connection.commit();
        }
    }
}
